package com.ai.bitcoin.service.helper;

import com.ai.bitcoin.constant.UrlConstant;
import com.ai.bitcoin.constant.WeiXinConfig;
import com.ai.bitcoin.constant.WeiXinPayContants;
import com.ai.bitcoin.util.JacksonUtils;
import com.ai.bitcoin.utils.HttpClientUtils;
import com.ai.bitcoin.utils.MD5;
import com.ai.bitcoin.weixin.DomManager;
import com.ai.bitcoin.weixin.WeiXinCallBackDom;
import com.ai.bitcoin.weixin.WeixinDom;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;



/**
 *
 *
 */
public abstract class WeiXinPayServiceHelper {

    private static final Logger logger = LoggerFactory.getLogger(WeiXinPayServiceHelper.class);

    private static final Map<String, Object> constantParam = new TreeMap<String, Object>();

    static {
        constantParam.put("appid", WeiXinPayContants.APPID);
        constantParam.put("mch_id", WeiXinPayContants.MCH_ID);
    }


    private static String formateRequest(TreeMap<String, Object> map) {

        if (map == null || map.isEmpty()) {
            return null;
        }

        map.putAll(constantParam);
        if (logger.isDebugEnabled()) {
            logger.debug("appid->mchid-->" + constantParam.toString());
        }
        map.put("sign", paramSign(map));
        return DomManager.createXml(new WeixinDom(), map);
    }


    public static String formateRequestString(TreeMap<String, Object> map) {
        return WeiXinPayServiceHelper.formateRequest(map);
    }

    /**
     * @param param
     * @return
     */
    public static Map<String, Object> preOrder(TreeMap<String, Object> param) {
        String resquestData = WeiXinPayServiceHelper.formateRequest(param);

        String rep = null;
        try {
            rep = HttpClientUtils.doPost(WeiXinConfig.PRE_ORDER, resquestData);
        } catch (Exception e) {
            logger.error("weixin pre order request ocurred error,url ="
                    + " {" + WeiXinConfig.PRE_ORDER + "}  request = {" + resquestData + "}" + "  repsonse = {" + rep + "}", e);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("return prepay msg --> {}",rep);
        }

        if (StringUtils.isNotBlank(rep)) {
            //parse weixin pay response
            WeiXinPayResult weiXinPayResult = DomManager.parseXml(new WeixinDom(), rep);

            Map<String, Object> prePayReturnMap = new HashMap<String, Object>();
            prePayReturnMap.put("returnCode", weiXinPayResult.getReturn_code());

            //return_code
            String returnCode = weiXinPayResult.getReturn_code();
            if (StringUtils.equals(returnCode, WeiXinPayContants.RESULT_CODE_FAIL)) {
                //communication fail
                prePayReturnMap.put("returnMsg", weiXinPayResult.getReturn_msg());
                return prePayReturnMap;
            } else {
                //communcation success
                String resultCode = weiXinPayResult.getResult_code();
                prePayReturnMap.put("resultCode", weiXinPayResult.getResult_code());
                if (StringUtils.equals(resultCode, WeiXinPayContants.RESULT_CODE_SUCCESS)) {
                    //success
                    prePayReturnMap.put("prePayId", weiXinPayResult.getPrepay_id());
                    prePayReturnMap.put("codeUrl",weiXinPayResult.getCode_url());
                    return prePayReturnMap;
                } else {
                    // procession fail
                    prePayReturnMap.put("errorDesc", weiXinPayResult.getErr_code_des());
                    return prePayReturnMap;
                }
            }

        }
        return null;
    }

    public static String buildCallBackUrl(String source) {
        StringBuilder url = new StringBuilder(UrlConstant.PAY_CALL_URL);
        url.append(source).append("/").append("notify");
        return url.toString();
    }

    /**
     * @param map
     * @return
     */
    public static String paramSign(Map<String, Object> map) {

        StringBuilder stringA = new StringBuilder();
        for (Entry<String, Object> entry : map.entrySet()) {
            stringA.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        stringA.deleteCharAt(stringA.length() - 1);
        stringA.append("&").append("key=").append(WeiXinPayContants.WEIXIN_PARAM_KEY);

        return StringUtils.upperCase(MD5.md5(stringA.toString()));
    }


    public static Boolean confirmPayCash(Long actualCash, WeixinCallBackResult weixinCallBackResult) {


        return null;
    }

    public static Map<String, Object> deposit(String resp) {
        if (StringUtils.isNotBlank(resp)) {
            //parse weixin pay response
            WeixinCallBackResult weixinCallBackResult = DomManager.parseXml(new WeiXinCallBackDom(), resp);

            Map<String, Object> refundReturnMap = new HashMap<String, Object>();
            refundReturnMap.put("returnCode", weixinCallBackResult.getReturn_code());

            //return_code
            String returnCode = weixinCallBackResult.getReturn_code();
            if (StringUtils.equals(returnCode, WeiXinPayContants.RESULT_CODE_FAIL)) {
                //communication fail
                refundReturnMap.put("returnMsg", weixinCallBackResult.getReturn_msg());
                return refundReturnMap;
            } else {
                //communcation success
                String resultCode = weixinCallBackResult.getResult_code();
                refundReturnMap.put("resultCode", weixinCallBackResult.getResult_code());
                if (StringUtils.equals(resultCode, WeiXinPayContants.RESULT_CODE_SUCCESS)) {
                    //success
                    return refundReturnMap;
                } else {
                    // procession fail
                    refundReturnMap.put("errorDesc", weixinCallBackResult.getErr_code_des());
                    return refundReturnMap;
                }
            }
        }
        return null;
    }

    public static class WeiXinPayResult {
        private String return_code;
        private String return_msg;
        //		private String appid;
//		private String mch_id;
        private String detail;
        private String nonce_str;
        private String result_code;
        private String err_code;
        private String err_code_des;

        private String trade_type;
        private String prepay_id;
        private String code_url;

        public WeiXinPayResult() {
        }

        public WeiXinPayResult(String return_code, String return_msg, String detail, String nonce_str, String result_code,
                               String err_code, String err_code_des, String trade_type, String prepay_id, String code_url) {
            this.return_code = return_code;
            this.return_msg = return_msg;
            this.detail = detail;
            this.nonce_str = nonce_str;
            this.result_code = result_code;
            this.err_code = err_code;
            this.err_code_des = err_code_des;
            this.trade_type = trade_type;
            this.prepay_id = prepay_id;
            this.code_url = code_url;
        }

        public String getReturn_code() {
            return return_code;
        }

        public void setReturn_code(String return_code) {
            this.return_code = return_code;
        }

        public String getReturn_msg() {
            return return_msg;
        }

        public void setReturn_msg(String return_msg) {
            this.return_msg = return_msg;
        }

        public String getDetail() {
            return detail;
        }

        public void setDetail(String detail) {
            this.detail = detail;
        }

        public String getNonce_str() {
            return nonce_str;
        }

        public void setNonce_str(String nonce_str) {
            this.nonce_str = nonce_str;
        }

        public String getResult_code() {
            return result_code;
        }

        public void setResult_code(String result_code) {
            this.result_code = result_code;
        }

        public String getErr_code() {
            return err_code;
        }

        public void setErr_code(String err_code) {
            this.err_code = err_code;
        }

        public String getErr_code_des() {
            return err_code_des;
        }

        public void setErr_code_des(String err_code_des) {
            this.err_code_des = err_code_des;
        }

        public String getTrade_type() {
            return trade_type;
        }

        public void setTrade_type(String trade_type) {
            this.trade_type = trade_type;
        }

        public String getPrepay_id() {
            return prepay_id;
        }

        public void setPrepay_id(String prepay_id) {
            this.prepay_id = prepay_id;
        }

        public String getCode_url() {
            return code_url;
        }

        public void setCode_url(String code_url) {
            this.code_url = code_url;
        }

    }

    public static final class WeixinCallBackResult {

        private String appid;
        private String bank_type;
        private Integer cash_fee;
        private String fee_type;
        private String is_subscribe;
        private String mch_id;
        private String nonce_str;
        private String openid;
        private String out_trade_no;

        private String result_code;
        private String return_code;
        private String sign;
        private String time_end;
        private Integer total_fee;
        private String trade_type;
        private String transaction_id;


        //weixin coupon
        private Integer coupon_count;
        private Integer coupon_fee;
        //		private String coupon_id_$n	;
//		private Integer coupon_fee_$n;
        private String coupon_id_0;
        private String coupon_id_1;
        private String coupon_id_2;
        private String coupon_id_3;
        private String coupon_id_4;

        private Integer coupon_fee_0;
        private Integer coupon_fee_1;
        private Integer coupon_fee_2;
        private Integer coupon_fee_3;
        private Integer coupon_fee_4;


        //fail field
        private String err_code;
        private String err_code_des;
        private String return_msg;


        //deposit field
//        private String mch_billno;
//        private String wxappid;
//        private String re_openid;
//        private String send_listid;
//        private Integer total_amount;

//        //refund field
//        private String out_refund_no;
//        private String refund_id;
//        private String refund_fee;


        public String getReturn_code() {
            return return_code;
        }

        public void setReturn_code(String return_code) {
            this.return_code = return_code;
        }

        public String getReturn_msg() {
            return return_msg;
        }

        public void setReturn_msg(String return_msg) {
            this.return_msg = return_msg;
        }

        public String getSign() {
            return sign;
        }

        public void setSign(String sign) {
            this.sign = sign;
        }

        public String getResult_code() {
            return result_code;
        }

        public void setResult_code(String result_code) {
            this.result_code = result_code;
        }

        public String getErr_code() {
            return err_code;
        }

        public void setErr_code(String err_code) {
            this.err_code = err_code;
        }

        public String getErr_code_des() {
            return err_code_des;
        }

        public void setErr_code_des(String err_code_des) {
            this.err_code_des = err_code_des;
        }

        public Integer getCash_fee() {
            return cash_fee;
        }

        public void setCash_fee(Integer cash_fee) {
            this.cash_fee = cash_fee;
        }

        public String getOut_trade_no() {
            return out_trade_no;
        }

        public void setOut_trade_no(String out_trade_no) {
            this.out_trade_no = out_trade_no;
        }

        public String getAppid() {
            return appid;
        }

        public void setAppid(String appid) {
            this.appid = appid;
        }

        public String getBank_type() {
            return bank_type;
        }

        public void setBank_type(String bank_type) {
            this.bank_type = bank_type;
        }

        public String getFee_type() {
            return fee_type;
        }

        public void setFee_type(String fee_type) {
            this.fee_type = fee_type;
        }

        public String getIs_subscribe() {
            return is_subscribe;
        }

        public void setIs_subscribe(String is_subscribe) {
            this.is_subscribe = is_subscribe;
        }

        public String getMch_id() {
            return mch_id;
        }

        public void setMch_id(String mch_id) {
            this.mch_id = mch_id;
        }

        public String getNonce_str() {
            return nonce_str;
        }

        public void setNonce_str(String nonce_str) {
            this.nonce_str = nonce_str;
        }

        public String getOpenid() {
            return openid;
        }

        public void setOpenid(String openid) {
            this.openid = openid;
        }

        public String getTime_end() {
            return time_end;
        }

        public void setTime_end(String time_end) {
            this.time_end = time_end;
        }

        public Integer getTotal_fee() {
            return total_fee;
        }

        public void setTotal_fee(Integer total_fee) {
            this.total_fee = total_fee;
        }

        public String getTrade_type() {
            return trade_type;
        }

        public void setTrade_type(String trade_type) {
            this.trade_type = trade_type;
        }

        public String getTransaction_id() {
            return transaction_id;
        }

        public void setTransaction_id(String transaction_id) {
            this.transaction_id = transaction_id;
        }


        public Integer getCoupon_count() {
            return coupon_count;
        }

        public void setCoupon_count(Integer coupon_count) {
            this.coupon_count = coupon_count;
        }

        public Integer getCoupon_fee() {
            return coupon_fee;
        }

        public void setCoupon_fee(Integer coupon_fee) {
            this.coupon_fee = coupon_fee;
        }

        public String getCoupon_id_0() {
            return coupon_id_0;
        }

        public void setCoupon_id_0(String coupon_id_0) {
            this.coupon_id_0 = coupon_id_0;
        }

        public String getCoupon_id_1() {
            return coupon_id_1;
        }

        public void setCoupon_id_1(String coupon_id_1) {
            this.coupon_id_1 = coupon_id_1;
        }

        public String getCoupon_id_2() {
            return coupon_id_2;
        }

        public void setCoupon_id_2(String coupon_id_2) {
            this.coupon_id_2 = coupon_id_2;
        }

        public String getCoupon_id_3() {
            return coupon_id_3;
        }

        public void setCoupon_id_3(String coupon_id_3) {
            this.coupon_id_3 = coupon_id_3;
        }

        public String getCoupon_id_4() {
            return coupon_id_4;
        }

        public void setCoupon_id_4(String coupon_id_4) {
            this.coupon_id_4 = coupon_id_4;
        }

        public Integer getCoupon_fee_0() {
            return coupon_fee_0;
        }

        public void setCoupon_fee_0(Integer coupon_fee_0) {
            this.coupon_fee_0 = coupon_fee_0;
        }

        public Integer getCoupon_fee_1() {
            return coupon_fee_1;
        }

        public void setCoupon_fee_1(Integer coupon_fee_1) {
            this.coupon_fee_1 = coupon_fee_1;
        }

        public Integer getCoupon_fee_2() {
            return coupon_fee_2;
        }

        public void setCoupon_fee_2(Integer coupon_fee_2) {
            this.coupon_fee_2 = coupon_fee_2;
        }

        public Integer getCoupon_fee_3() {
            return coupon_fee_3;
        }

        public void setCoupon_fee_3(Integer coupon_fee_3) {
            this.coupon_fee_3 = coupon_fee_3;
        }

        public Integer getCoupon_fee_4() {
            return coupon_fee_4;
        }

        public void setCoupon_fee_4(Integer coupon_fee_4) {
            this.coupon_fee_4 = coupon_fee_4;
        }

        @Override
        public String toString() {
            return JacksonUtils.toJson(this);
        }

    }
}